package com.sam.contact;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.Contacts.Data;
import android.provider.ContactsContract.RawContacts;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import au.com.bytecode.opencsv.CSVReader;
import au.com.bytecode.opencsv.CSVWriter;

import com.lamerman.FileDialog;

public class ContactTool extends Activity implements OnClickListener{

	private static final String TAG = "ImportContactList";
	
	private static final int IMPORT_MSG_TYPE_MAX = 1;
	private static final int IMPORT_MSG_TYPE_INCREMENT = 2;
	private static final int IMPORT_MSG_TYPE_FINISHED = 3;
	
	private static final int EXPORT_MSG_TYPE_MAX = 4;
	private static final int EXPORT_MSG_TYPE_INCREMENT = 5;
	private static final int EXPORT_MSG_TYPE_FINISHED = 6;
	
	private static final int REQ_CODE_SELECT = 1;
	
	private static final String[] TITLE_LINE = {"Name","Mobile Number","Home Number","Work Number","Email"};
	
	private static final String DEF_IMPORT_FILE_PATH = "/sdcard/contactList.csv";
	private static final String DEF_EXPORT_FILE_PATH_PREFIX = "/sdcard/contactList";
	private static final String DEF_EXPORT_FILE_PATH_SUFFIX = ".csv";
	
	private static final String DEF_CHARSET = "GBK";

	private TextView mainText;
	private ProgressBar progressBar;
	private EditText fileText;
	private Button fileSelBtn;
	private Button importBtn;
	private Button exportBtn;
	
	private Timer timer = new Timer();
	
	private Handler mHandler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			if (IMPORT_MSG_TYPE_MAX == msg.what) {
				
				mainText.setText(msg.arg1 + " records to be import...");
				if(msg.arg1 == 0){
					Toast toast = Toast.makeText(ContactTool.this, "No record to be import...", Toast.LENGTH_LONG);
					toast.show();
					
					enableClick();
				}else{
					progressBar.setMax(msg.arg1);
				}
			} else if (IMPORT_MSG_TYPE_INCREMENT == msg.what) {
				progressBar.incrementProgressBy(1);
			} else if (IMPORT_MSG_TYPE_FINISHED == msg.what) {
				mainText.setText("added " + msg.arg2 + " contacts from " + msg.arg1 + " records");
				enableClick();
				
			}else if(EXPORT_MSG_TYPE_MAX == msg.what){
				mainText.setText(msg.arg1 + " contacts to be export...");
				if(msg.arg1 == 0){
					Toast toast = Toast.makeText(ContactTool.this, "No contact to be export...", Toast.LENGTH_LONG);
					toast.show();
					
					enableClick();
				}else{
					progressBar.setMax(msg.arg1);
				}
			} else if (EXPORT_MSG_TYPE_INCREMENT == msg.what) {
				progressBar.incrementProgressBy(1);
			}else if (EXPORT_MSG_TYPE_FINISHED == msg.what) {
				mainText.setText("imported " + msg.arg2 + " contacts to file " + msg.arg1);
				
				enableClick();
			}

		}

		private void enableClick() {
			progressBar.setVisibility(View.GONE);
			fileSelBtn.setEnabled(true);
			importBtn.setEnabled(true);
			exportBtn.setEnabled(true);
		}

	};

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		mainText = (TextView) this.findViewById(R.id.mainText);
		progressBar = (ProgressBar) this.findViewById(R.id.progress_horizontal);
		fileText = (EditText)this.findViewById(R.id.fileText);
		fileSelBtn = (Button)this.findViewById(R.id.fileSelBtn);
		importBtn = (Button)this.findViewById(R.id.importBtn);
		exportBtn = (Button)this.findViewById(R.id.exportBtn);
		fileSelBtn.setOnClickListener(this);
		importBtn.setOnClickListener(this);
		exportBtn.setOnClickListener(this);
	}
	
	public void onClick(View v) {
		Intent intent;
		switch (v.getId()) {
		case R.id.fileSelBtn:
			intent = new Intent(this, FileDialog.class);
			intent.putExtra(FileDialog.START_PATH, "/sdcard");
			this.startActivityForResult(intent, REQ_CODE_SELECT);
			break;
		case R.id.importBtn:
			disableClick();
			
			timer.schedule(new ImportTask(), 100);

			break;
		case R.id.exportBtn:
			disableClick();
			
			timer.schedule(new ExportTask(), 100);
			break;
		}

	}

	private void disableClick() {
		fileSelBtn.setEnabled(false);
		importBtn.setEnabled(false);
		exportBtn.setEnabled(false);
		
		progressBar.setVisibility(View.VISIBLE);
	}
	
	

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if(REQ_CODE_SELECT == requestCode && RESULT_OK == resultCode){
			String path = data.getStringExtra(FileDialog.RESULT_PATH);
			fileText.setText(path);
		}
		
	}
	
	private class ImportTask extends TimerTask {
		@Override
		public void run() {
			String filePath = fileText.getText().toString();
			if(filePath == null || filePath.trim().length() == 0){
				filePath = DEF_IMPORT_FILE_PATH;
			}
			
			File listFile = new File(filePath);
			

			
			if (!listFile.exists()) {
				Log.e(TAG, "contact list file '" +filePath + "' not exist, please check.");
			} else {
				importFile(listFile);
			}
		}
	}
	
	private class ExportTask extends TimerTask {
		@Override
		public void run() {
			String filePath = fileText.getText().toString();
			if(filePath == null || filePath.trim().length() == 0){
				String dateStr = (String) DateFormat.format("yyyyMMdd", new Date());
				filePath = DEF_EXPORT_FILE_PATH_PREFIX + dateStr + DEF_EXPORT_FILE_PATH_SUFFIX;
			}
			File listFile = new File(filePath);

			exportFile(listFile);
		}
	}

	
	private void importFile(File listFile) {
		try {
			
			InputStreamReader isr = new InputStreamReader(new FileInputStream(listFile), DEF_CHARSET);

			CSVReader csvReader = new CSVReader(isr);

			List<String[]> lineList = csvReader.readAll();
			csvReader.close();
			
			int size = lineList.size();

			// send message to update the progressbar's max value
			Message msg = mHandler.obtainMessage();
			msg.what = IMPORT_MSG_TYPE_MAX;
			msg.arg1 = size -1;
			msg.sendToTarget();

			ContentResolver contentResolver = this.getContentResolver();

			String name;
			String mobleNumber;
			String homeNumber;
			String workNumber;
			String email;

			int insertedCount = 0;

			for (int i = 0; i < size; i++) {
				if (i == 0) {
					// skip the title line
					continue;
				}

				name = null;
				mobleNumber = null;
				homeNumber = null;
				workNumber = null;
				email = null;

				String[] lineArr = lineList.get(i);
				int len = lineArr.length;

				if (len >= 1) {
					name = lineArr[0];
				}

				if (len >= 2) {
					mobleNumber = lineArr[1];
				}

				if (len >= 3) {
					homeNumber = lineArr[2];
				}

				if (len >= 4) {
					workNumber = lineArr[3];
				}

				if (len >= 5) {
					email = lineArr[4];
				}


				if (insertContactBatch(contentResolver, name, mobleNumber, homeNumber, workNumber, email)) {
					insertedCount++;
					// send message to increment the progressbar's progress
					msg = mHandler.obtainMessage();
					msg.what = IMPORT_MSG_TYPE_INCREMENT;
					msg.sendToTarget();
				}
			}

			// send message to notify that the import was finished
			msg = mHandler.obtainMessage();
			msg.what = IMPORT_MSG_TYPE_FINISHED;
			msg.arg1 = size -1;
			msg.arg2 = insertedCount;
			msg.sendToTarget();

		} catch (Exception e) {
			Log.i(TAG, e.toString());
		}
		
	}

	
	private void exportFile(File listFile) {
		try {
			List<String[]> contactList = getContact(this.getContentResolver());
			
			int size = 0;
			if(contactList != null){
				size = contactList.size();

				// send message to update the progressbar's max value
				Message msg = mHandler.obtainMessage();
				msg.what = EXPORT_MSG_TYPE_MAX;
				msg.arg1 = size;
				msg.sendToTarget();
				
				if(size == 0){
					Log.i(TAG, "no contact to be export");
					return;
				}
			}
			
			OutputStreamWriter  osw = new OutputStreamWriter(new FileOutputStream(listFile), DEF_CHARSET);
			
			CSVWriter writer = new CSVWriter(osw);
			//write title line
			writer.writeNext(TITLE_LINE);
			
			for(String[] contanctArr : contactList){
				writer.writeNext(contanctArr);
				
				// send message to increment the progressbar's progress
				Message msg = mHandler.obtainMessage();
				msg.what = EXPORT_MSG_TYPE_INCREMENT;
				msg.sendToTarget();
			}
			
			// send message to notify that the import was finished
			Message msg = mHandler.obtainMessage();
			msg.what = EXPORT_MSG_TYPE_FINISHED;
			msg.arg1 = size;
			msg.sendToTarget();
			
			
			writer.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/** * 获取通讯录中联系人 */
	public List<String[]> getContact(ContentResolver contentResolver) {
		Cursor cursor = contentResolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);

		
		List<String[]> contactList = null;
		
		
		if (cursor.moveToFirst()) {
			contactList = new ArrayList<String[]>();
			do {
				String[] contanctArr = new String[5];
				// 获取联系人姓名
				String contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
				String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
				contanctArr[0] = name;
				
				// 获取联系人手机号码
				Cursor phones = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
						ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + contactId, null, null);
				while (phones.moveToNext()) {
					int type = phones.getInt(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));
					String number = null;
					switch (type){
					case Phone.TYPE_MOBILE:
						number = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
						contanctArr[1] = number;
						break;
					case Phone.TYPE_HOME:
						number = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
						contanctArr[2] = number;
						break;
					case Phone.TYPE_WORK:
						number = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
						contanctArr[3] = number;
						break;
					}
				}
				// 获取联系人email
				Cursor emails = contentResolver.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, null,
						ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = " + contactId, null, null);
				while (emails.moveToNext()) {
					int type = emails.getInt(emails.getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE));
					String email = null;
					switch (type){
					case Phone.TYPE_MOBILE:
						email = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
						contanctArr[4] = email;
						break;

					}
				}
				
				contactList.add(contanctArr);

			} while (cursor.moveToNext());
		}
		return contactList;
	}

	public boolean insertContactBatch(ContentResolver contentResolver, String name, String mobleNumber,
			String homeNumber, String workNumber, String email) {

		ArrayList<ContentProviderOperation> cpoList = new ArrayList<ContentProviderOperation>();
		int rawContactInsertIndex = 0;
		cpoList.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI).withValue(RawContacts.ACCOUNT_TYPE, null)
				.withValue(RawContacts.ACCOUNT_NAME, null).build());
		
		// 文档位置：reference\android\provider\ContactsContract.Data.html
		//insert name
		if(name != null && name.length() > 0){
			cpoList.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
					.withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
					.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
					.withValue(StructuredName.GIVEN_NAME, name)
					.build());
		}
		
		//insert mobile number
		if(mobleNumber != null && mobleNumber.length() > 0){
			cpoList.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
					.withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
					.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
					.withValue(Phone.TYPE, Phone.TYPE_MOBILE)
					.withValue(Phone.NUMBER, mobleNumber)
					.build());
		}
		
		//insert home number
		if(homeNumber != null && homeNumber.length() > 0){
			cpoList.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
					.withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
					.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
					.withValue(Phone.TYPE, Phone.TYPE_HOME)
					.withValue(Phone.NUMBER, homeNumber)
					.build());
		}
		
		//insert work number
		if(workNumber != null && workNumber.length() > 0){
			cpoList.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
					.withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
					.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
					.withValue(Phone.TYPE, Phone.TYPE_WORK)
					.withValue(Phone.NUMBER, workNumber)
					.build());
		}
		
		//insert email number
		if(email != null && email.length() > 0){
			cpoList.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
					.withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
					.withValue(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE)
					.withValue(Email.TYPE, Email.TYPE_WORK)
					.withValue(Email.DATA, email)
					.build());
		}
		
		//insert group
		/*if(group != null && group.length() > 0){
			cpoList.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
					.withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
					.withValue(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE)
					.withValue(GroupMembership.DATA1, group)
					.build());
		}*/
		try {
			ContentProviderResult[] results = contentResolver.applyBatch(ContactsContract.AUTHORITY, cpoList);
			Log.e(TAG, "insert successfully. name:" + name );
		} catch (Exception e) {
			Log.e(TAG, e.toString());
			return false;
		}

		return true;

		// 往data表入Email数据 values.clear();
		/*
		 * values.put(android.provider.ContactsContract.Contacts.Data.RAW_CONTACT_ID
		 * , rawContactId); values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
		 * values.put(Email.DATA, "ljq218@126.com"); values.put(Email.TYPE,
		 * Email.TYPE_WORK);
		 * this.getContentResolver().insert(android.provider.ContactsContract
		 * .Data.CONTENT_URI, values);
		 */
	}

	/**
	 * 首先向RawContacts.CONTENT_URI执行一个空值插入，目的是获取系统返回的rawContactId
	 * 
	 * 这是后面插入data表的数据，只有执行空值插入，才能使插入的联系人在通讯录里可见
	 * 
	 * @param group
	 * @param email
	 * @param workNumber
	 * */
	public boolean insertContact(ContentResolver contentResolver, String name, String mobleNumber, String homeNumber,
			String workNumber, String email, String group) {
		List<ContentProviderOperation> cpoList = new ArrayList<ContentProviderOperation>();

		ContentValues values = new ContentValues();
		// 首先向RawContacts.CONTENT_URI执行一个空值插入，目的是获取系统返回的rawContactId
		// ContentResolver contentResolver = this.getContentResolver();
		Uri rawContactUri = contentResolver.insert(RawContacts.CONTENT_URI, values);
		long rawContactId = ContentUris.parseId(rawContactUri);

		cpoList.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
				.withValue(RawContacts.ACCOUNT_TYPE, null).withValue(RawContacts.ACCOUNT_NAME, null).build());

		Log.i(TAG, "rawContactId:" + rawContactId);
		// 往data表入姓名数据 values.clear();
		values.put(Data.RAW_CONTACT_ID, rawContactId);
		values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
		values.put(StructuredName.GIVEN_NAME, name);
		contentResolver.insert(android.provider.ContactsContract.Data.CONTENT_URI, values);

		// 往data表入mobile电话数据 values.clear();
		if (mobleNumber != null) {
			values.put(android.provider.ContactsContract.Contacts.Data.RAW_CONTACT_ID, rawContactId);
			values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
			values.put(Phone.NUMBER, mobleNumber);
			values.put(Phone.TYPE, Phone.TYPE_MOBILE);
			contentResolver.insert(android.provider.ContactsContract.Data.CONTENT_URI, values);
		}

		// 往data表入home电话数据 values.clear();
		if (homeNumber != null) {
			values.put(android.provider.ContactsContract.Contacts.Data.RAW_CONTACT_ID, rawContactId);
			values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
			values.put(Phone.NUMBER, homeNumber);
			values.put(Phone.TYPE, Phone.TYPE_HOME);

		}

		contentResolver.insert(android.provider.ContactsContract.Data.CONTENT_URI, values);

		return true;

		// 往data表入Email数据 values.clear();
		/*
		 * values.put(android.provider.ContactsContract.Contacts.Data.RAW_CONTACT_ID
		 * , rawContactId); values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
		 * values.put(Email.DATA, "ljq218@126.com"); values.put(Email.TYPE,
		 * Email.TYPE_WORK);
		 * this.getContentResolver().insert(android.provider.ContactsContract
		 * .Data.CONTENT_URI, values);
		 */
	}

}